/**
 * @author https://xhcss.com/Browser/article/141
 */
import CryptoJS from "crypto-js";
import WebSocket from "ws";
import fs from "fs";
const path = require("path");
const APPID = process.env.XH_APPID;
const API_SECRET = process.env.XH_API_SECRET;
const API_KEY = process.env.XH_API_KEY;
function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}
const FRAME = {
  STATUS_FIRST_FRAME: 0,
  STATUS_CONTINUE_FRAME: 1,
  STATUS_LAST_FRAME: 2,
};

const config = {
  // 请求地址
  hostUrl: "wss://iat-api.xfyun.cn/v2/iat",
  host: "iat-api.xfyun.cn",
  //在控制台-我的应用-语音听写（流式版）获取
  appid: process.env.XH_APPID,
  //在控制台-我的应用-语音听写（流式版）获取
  apiSecret: process.env.XH_API_SECRET,
  //在控制台-我的应用-语音听写（流式版）获取
  apiKey: process.env.XH_API_KEY,
  uri: "/v2/iat",
  highWaterMark: 1280,
};

/**
 * 获取携带token的  webscoket url
 * @param href 如果携带了连接，则以此为准
 * @returns url
 */

function getAuthStr(date: any) {
  let signatureOrigin = `host: ${config.host}\ndate: ${date}\nGET ${config.uri} HTTP/1.1`;
  let signatureSha = CryptoJS.HmacSHA256(signatureOrigin, config.apiSecret);
  let signature = CryptoJS.enc.Base64.stringify(signatureSha);
  let authorizationOrigin = `api_key="${config.apiKey}", algorithm="hmac-sha256", headers="host date request-line", signature="${signature}"`;
  let authStr = CryptoJS.enc.Base64.stringify(
    CryptoJS.enc.Utf8.parse(authorizationOrigin)
  );
  return authStr;
}
export const getWebsocketUrl = (
  apiKey?: string,
  apiSecret?: string
): string => {
  let date = new Date().toUTCString();
  let wssUrl =
    config.hostUrl +
    "?authorization=" +
    getAuthStr(date) +
    "&date=" +
    date +
    "&host=" +
    config.host;
  return wssUrl;
};

/**
 * websockets 封装类
 */
class SocketsXfVoice {
  url?: string; // 连接地址
  socket?: any; // socket实类
  isOnline: boolean; // 是否连接 , 这里是考虑到每次只能发送一条，一条结束前，为true则不能让人继续发消息
  APPID: string;
  data: string[]; // 一条消息星火模型会多次webscoket 返回，所以进行拼接
  resolve?: any; // 成功后的回调
  reject?: any;
  callback?: Function;
  currentSid?: any;
  status: number;
  constructor(option?: ChatOption) {
    this.socket = undefined;
    this.isOnline = false;
    this.url = getWebsocketUrl(option?.API_KEY, option?.API_SECRET);
    this.APPID = option?.APPID ?? APPID;
    this.APPID = option?.APPID ?? APPID;
    this.callback = option?.callback;
    // 合并的消息
    this.data = [];
    this.resolve = undefined;
    this.reject = undefined;
    this.status = 0;
  }

  /**
   * 连接url
   * @returns WebSocket
   */
  connectSocket() {
    return new Promise((resolve, reject) => {
      if (this.socket && this.isOnline) {
        resolve(this.socket);
      } else {
        const url = this.url!;
        this.socket = new WebSocket(url);
        // 监听连接成功
        // 监听连接成功
        this.socket.onopen = () => {
          console.log("链接成功");
          this.isOnline = true;
          resolve(this.socket);
        };

        // 监听接收信息
        this.socket.onmessage = (e: any,err:any) => this.onMessage(e,err);
        // 监听断开
        this.socket.onclose = (e: any) => this.onclose(e);
        // 监听错误
        this.socket.onerror = (err: any) => {
          this.reject();
          console.log("链接错误1");
          //   console.log(err)
          this.isOnline = false;
        };
      }
    });
  }
  onclose(err: any) {
    console.log("链接关闭");
    //  console.log(err)
  }
  /**
   * 收到消息
   * @param data ChatFace
   */
  onMessage(data: MessageData, err) {
    console.log("收到消息");

    if (err) {
      console.log(`err:${err}`);
      return;
    }
    const res = JSON.parse(data.data);
    console.log(res.data.result.ws);

    if (res.code != 0) {
      console.log(`error code ${res.code}, reason ${res.message}`);
      return;
    }
    let str = "";
    this.data[res.data.result.sn] = res.data.result;
    if (res.data.result.pgs == "rpl") {
      res.data.result.rg.forEach((i) => {
        this.data[i] = null;
      });
      str += "【动态修正】";
    }

    str += "";
    this.data.forEach((i) => {
      if (i != null) {
        i.ws.forEach((j) => {
          j.cw.forEach((k) => {
            str += k.w;
          });
        });
      }
    });
    console.log(str);
    if (res.data.status == 2) {
      this.currentSid = res.sid;
      this.resolve(str);
      this.close();
    } else {
    }
  }
  /**
   * 主动关闭，暂时无用
   */
  close() {
    this.socket?.close();
    this.socket = undefined;
    this.isOnline = false;
    this.data = [];
    this.status = 0;
    console.log("关闭了");
    this.resolve = undefined;
  }

  sends(data: any) {
    let frame: any;
    let frameDataSection = {
      status: this.status,
      format: "audio/L16;rate=16000",
      audio: data.toString("base64"),
      encoding: "raw",
    };
    switch (this.status) {
      // 注意 status 0 和2一点要传入 代表开始和结束。而且只能传一次
      case FRAME.STATUS_FIRST_FRAME:
        frame = {
          common: {
            app_id: APPID,
          },
          business: {
            language: "zh_cn",
            domain: "iat",
            accent: "mandarin",
            dwa: "wpgs", // 可选参数，动态修正
          },
          //填充data
          data: frameDataSection,
        };
        this.status = FRAME.STATUS_CONTINUE_FRAME;
        break;
      case FRAME.STATUS_CONTINUE_FRAME:
      case FRAME.STATUS_LAST_FRAME:
        if (this.status === 2) {
          console.log("等于2");
        }
        //填充frame
        frame = {
          data: frameDataSection,
        };
        break;
    }
    this.socket.send(JSON.stringify(frame));
  }

  /**
   * 发送消息
   * @param str  发送的消息文字
   * @returns
   */

  send22(path: string): Promise<string> {
    const that = this;
    return new Promise((resolve, reject) => {
      that.resolve = resolve;
      this.connectSocket().then(async (res) => {

        var readerStream = fs.createReadStream(path, {
          highWaterMark: 1028,
        });
        readerStream.on("data", function (chunk) {
          that.sends(chunk);
        });
        // 最终帧发送结束
        readerStream.on("end", function () {

          console.log("消息结束");
          that.status = 2;
          that.sends("");
        });
      });
    });
  }
  send(decodedData: any): Promise<string> {
    const that = this;
    return new Promise((resolve, reject) => {
      that.resolve = resolve;
      this.connectSocket().then(async (res) => {
        const chunkSize = 1028;
        const chunkCount = Math.ceil(decodedData.length / chunkSize);
        let frame: any;
        for (let i = 0; i < chunkCount; i++) {
          const start = i * chunkSize;
          const end = Math.min(start + chunkSize, decodedData.length);
          const chunk = decodedData.slice(start, end);

          if (end == decodedData.length) {
            this.status = 2;
          }
          this.sends(chunk);
        }
      });
    });
  }
  fk() {}
}
export default SocketsXfVoice;

interface MessageData {
  data: string;
}
/**
 * 组件传入的字段
 */
interface ChatOption {
  uid?: string; // 传入的用户id
  url?: string; // 连接
  APPID?: string; // 传入的appid，便于让用户用自己的使用
  API_SECRET?: string;
  API_KEY?: string;
  callback?: Function; // 如果传入回调,则每次收到消息都会传回回调
}

interface ChatFace {
  code: number;
  message: "success";
  sid: "iatxxxxxxxxxxxxx";
  data: {
    result: {
      bg: 0;
      ed: 0;
      ls: false;
      sn: 1;
      ws: [
        {
          bg: 35;
          cw: [
            {
              sc: 0;
              w: string;
            },
            {
              sc: 0;
              w: string;
            }
          ];
        }
      ];
    };
    status: number;
  };
}
